﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Runtime.Serialization.Json;

using Finance.Common;
using Finance.Entites;
using Finance.Service.Interfaces;

namespace Finance.Service.Implements
{
    /// <summary>
    /// Store the data with json format in the disk
    /// </summary>
    /// <typeparam name="TEntity">The graph of store object contains in ObserableCollection</typeparam>
    public class JsonDataStore<TEntity> : IDataStore<TEntity>
    {
        #region Const Values

        private const string FileExtendName = ".json";
        private static readonly string DefaultFileName = typeof(TEntity).Name + FileExtendName;

        #endregion

        #region Fields and Properties

        /// <summary>
        /// The file name stored in the local disk
        /// </summary>
        public virtual string FileName { get; private set; }
        /// <summary>
        /// ObserableCollection contains the stored entity objects 
        /// </summary>
        protected ObservableCollection<TEntity> _Items = new ObservableCollection<TEntity>();
        /// <summary>
        /// ObserableCollection contains the stored entity objects 
        /// </summary>
        public virtual ObservableCollection<TEntity> Items
        {
            get
            {
                return _Items;
            }
            protected set
            {
                _Items = value;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Store the graph into the the file with default file name
        /// the file name is combine with type name of TEntity and the
        /// extend name is .json
        /// </summary>
        public JsonDataStore() : this(DefaultFileName) { }
        /// <summary>
        /// Store the graph into the the file with specify file name
        /// </summary>
        /// <param name="fileName">the file name</param>
        public JsonDataStore(string fileName)
        {
            FileName = fileName;
            Items = Items ?? new ObservableCollection<TEntity>();
            if (Items.IsNullOrEmpty()) { Load(); }
        }

        #endregion

        #region Implements Methods of IDataStore<TEntity>

        public virtual void Commit()
        {
            lock (this.GetType())
            {
                using (var fileStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    using (FileStream fs = fileStore.OpenFile(FileName, FileMode.Create))
                    {
                        var jsonSerializer =
                            new DataContractJsonSerializer(
                                typeof(ObservableCollection<TEntity>));
                        jsonSerializer.WriteObject(fs, Items);
                        fs.Close();
                    }
                }
            }
        }

        public virtual void Rollback()
        {
            Load();
        }

        #endregion

        #region Private or Protected Methods

        /// <summary>
        /// Load the data from local disk into the Items property
        /// </summary>
        protected virtual void Load()
        {
            lock (this.GetType())
            {
                using (var fileStore = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (fileStore.FileExists(FileName))
                    {
                        using (FileStream fs = fileStore.OpenFile(FileName, FileMode.Open))
                        {
                            var jsonSerializer =
                                new DataContractJsonSerializer(typeof(ObservableCollection<TEntity>));
                            var _tempDataContext = jsonSerializer.ReadObject(fs) as ObservableCollection<TEntity>;
                            Items.Clear();
                            if (_tempDataContext != null)
                            {
                                foreach (var tempItem in _tempDataContext)
                                {
                                    Items.Add(tempItem);
                                }
                            }
                            fs.Close();
                        }
                    }
                    else
                    {
                        fileStore.CreateFile(FileName);
                        Items = new ObservableCollection<TEntity>();
                    }
                }
            }
        }

        #endregion
    }
}